package com.example.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class JwtUtil {
    
    @Value("${jwt.secret}")
    private String secret; // 默认初始密钥
    @Value("${jwt.expiration}")
    private long expiration; // 令牌有效期（分钟）：30
    @Value("${jwt.refresh-threshold}")
    private long refreshThreshold; // 刷新阈值（分钟）：5

    // 安全密钥对象
    private SecretKey secretKey;

    /**
     * 初始化密钥，第一次使用时调用，避免过早初始化导致配置未加载
     * @return
     */
    private SecretKey getSecretKey() {
        if (secretKey == null) {
            if (secret == null || secret.getBytes().length < 32) {
                throw new IllegalStateException("JWT 密钥长度不足32字节（256位），存在安全风险");
            }
            secretKey = Keys.hmacShaKeyFor(secret.getBytes());
        }
        return secretKey;
    }

    /**
     * 生成JWT令牌
     * @param claims 自定义声明信息
     * @return JWT令牌字符串
     */
    public String generateToken(Map<String, Object> claims) {
        return generateToken(claims, expiration);
    }

    /**
     * 生成JWT令牌，包括自定义过期时间
     * @param claims  自定义声明信息
     * @param expirationMinutes 过期时间（分钟）
     * @return JWT令牌字符串
     */
    public String generateToken(Map<String, Object> claims, long expirationMinutes) {
        // 计算过期时间
        Date expirationDate = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(expirationMinutes));

        return Jwts.builder().claims(claims).issuedAt(new Date()).expiration(expirationDate).signWith(getSecretKey()).compact();
    }

    /**
     * 解析 JWT 令牌
     * @param token
     * @return
     */
    public Claims parseToken(String token) {
        return Jwts.parser().verifyWith(getSecretKey()).build().parseSignedClaims(token).getPayload();
    }

    /**
     * 验证令牌是否有效
     * @param token
     * @return
     */
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (ExpiredJwtException e) {
            // 令牌过期
            System.out.println("JWT令牌过期：" + e.getMessage());
        } catch (SignatureException e) {
            // 签名验证失败
            System.out.println("签名验证失败" + e.getMessage());
        } catch (MalformedJwtException e) {
            // 令牌格式错误
            System.out.println("令牌格式错误: " + e.getMessage());
        } catch (IllegalStateException e) {
            // 非法参数
            System.out.println("Jwt解析参数错误：" + e.getMessage());
        }
        return false;
    }

    public String refreshToken(String token) {
        try {
            Claims claims = parseToken(token);

            // 检查是否需要刷新：剩余想混小于刷新阈值
            Date expiration = claims.getExpiration();
            long remainingMillis = expiration.getTime() - System.currentTimeMillis();
            long thresholdMillis = TimeUnit.MINUTES.toMillis(refreshThreshold);

            if (remainingMillis < thresholdMillis) {
                // 不需要刷新
                return token;
            }

            // 刷新新胡声明映射
            HashMap<String, Object> newClaims = new HashMap<>(claims);
            // 移除签发时间肯过期时间
            newClaims.remove("iat");
            newClaims.remove("exp");

            // 生成新令牌
            return generateToken(newClaims);
        } catch (ExpiredJwtException e) {
            // 令牌已过期，需要重新的登录
            throw new SecurityException("令牌已过期，需要重新的登录");
        } catch (Exception e) {
            throw new SecurityException("令牌刷新失败：" + e.getMessage());
        }
    }
}
